#ifndef _UDPSERVER_HPP_
#define _UDPSERVER_HPP_ 

#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using std::string;

struct ClientInfo
{
  bool isRecv = false;
  string ip;
  uint16_t port;
};

class UdpServer 
{
public:
  UdpServer(uint16_t port)
    :_port(port), _socket(-1)
  {
    // udp服务器的初始化在这里完成：套接字的创建与绑定即可
    _socket = socket(AF_INET, SOCK_DGRAM, 0);  // 网络IPV4协议通信，基于数据报 自动推导UDP通信
    if (_socket < 0)
    {
      // 报错处理
      std::cerr << "socket error: " << strerror(errno) << "\n";
      exit(errno);
    }
    // 成功创建对应套接字描述符
    // 绑定IP和端口
    struct sockaddr_in server;
    memset(&server, 0, sizeof server);
    server.sin_family = AF_INET;
    server.sin_port = htons(_port);  // 本地端口转网络字节序
    server.sin_addr.s_addr = inet_addr("0.0.0.0"); // 本地ip转网络字节序 本地测试可以是127.0.0.1
    if (0 > bind(_socket, (sockaddr*)&server,sizeof server))
    {
      // 绑定失败
      std::cerr << "bind error: " << strerror(errno) << "\n";
      exit(errno);
    }
    std::cout << "UDPServer init succeed......\n";
    // 绑定成功 UdpServer 服务准备就绪
  }

  ~UdpServer()
  {
    if (_socket > 0) close(_socket);
  }

  // udp服务器提供的功能
  
  // 发送信息功能
  // 客户端ip、客户端端口、发送的信息
  // 注意是阻塞方式进行发送信息
  bool SendMessage(const string& clientIp, const uint16_t clientPort, const string& message)
  {
    // 创建发送客户端的结构体
    struct sockaddr_in client;
    memset(&client, 0, sizeof client);
    client.sin_family = AF_INET;
    client.sin_port = htons(clientPort);
    client.sin_addr.s_addr = inet_addr(clientIp.c_str());

    // 发送本体
    int flag = sendto(_socket, message.c_str(), message.size(), 0, (sockaddr*)&client, sizeof client);
    if (flag < 0) std::cerr << "sendto error: " << strerror(errno) << "\n";
    return flag >= 0;
  }

  // 接收信息的功能
  ClientInfo RecvMessage(string& message)
  {
    struct ClientInfo clientInfo;

    char receiveBuffer[1024] = {0};  // 接收缓冲区
    struct sockaddr_in client;
    socklen_t clientSize = sizeof client;
    memset(&client, 0, sizeof client);
    
    int n = recvfrom(_socket, receiveBuffer, sizeof(receiveBuffer) - 1, 0, (sockaddr*)&client, &clientSize);
    if (n < 0) std::cerr << "recvfrom error: " << strerror(errno) << "\n";
    else{
      // 对发送方进行解析
      clientInfo.ip = inet_ntoa(client.sin_addr);  // 网络字节序转换为本地字节序
      clientInfo.port = ntohs(client.sin_port);
      receiveBuffer[n] = '\0'; 
      message = receiveBuffer;
      clientInfo.isRecv = true;
    }

    return clientInfo; 
  }

private:
  uint16_t  _port;
  int _socket;
};








#endif
